<template>
  <div class="app-container">
    <el-form :model="queryParams" ref="queryForm" :inline="true" class="demo-form-inline">
      <el-form-item label="菜单名称" prop="menuName">
        <el-input v-model="queryParams.menuName" placeholder="请输入菜单名称" clearable @keyup.enter="handleQuery" />
      </el-form-item>
      <el-form-item label="状态">
        <el-select v-model="queryParams.status" placeholder="菜单状态" clearable style="width: 240px">
          <el-option label="正常" value="0" />
          <el-option label="停用" value="1" />
        </el-select>
      </el-form-item>
      <el-form-item>
        <el-button type="primary" @click="handleQuery">搜索</el-button>
        <el-button @click="resetQuery">重置</el-button>
      </el-form-item>
    </el-form>
    <el-row :gutter="10" class="mb8">
      <el-col :span="1.5">
        <el-button type="primary" plain @click="handleAdd">新增</el-button>
      </el-col>
      <el-col :span="1.5">
        <el-button type="info" plain @click="toggleExpandAll">展开/折叠</el-button>
      </el-col>
    </el-row>
    <el-table
      v-if="refreshTable"
      v-loading="loading"
      :data="menuList"
      row-key="menuId"
      :default-expand-all="isExpandAll"
      :tree-props="{ children: 'children', hasChildren: 'hasChildren' }"
    >
      <el-table-column prop="menuName" label="菜单名称" :show-overflow-tooltip="true" width="160"></el-table-column>
      <el-table-column prop="icon" label="图标" align="center" width="100">
        <template v-slot="scope">
          <el-icon>
            <component :is="scope.row.icon"></component>
          </el-icon>
        </template>
      </el-table-column>
      <el-table-column prop="orderNum" label="排序" width="60"></el-table-column>
      <el-table-column prop="perms" label="权限标识" :show-overflow-tooltip="true"></el-table-column>
      <el-table-column prop="component" label="组件路径" :show-overflow-tooltip="true"></el-table-column>
      <el-table-column prop="status" label="状态" width="80">
        <template v-slot="scope">
          <el-tag type="" v-if="scope.row.status === '0'">正常</el-tag>
          <el-tag type="danger" v-else>停用</el-tag>
        </template>
      </el-table-column>
      <el-table-column label="创建时间" align="center" prop="createTime"></el-table-column>
      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
        <template v-slot="scope">
          <el-button link type="primary" @click="handleUpdate(scope.row)">修改</el-button>
          <el-button link type="primary" @click="handleAdd(scope.row)">新增</el-button>
          <el-button link type="primary" @click="handleDelete(scope.row)">删除</el-button>
        </template>
      </el-table-column>
    </el-table>
    <!-- 添加或修改菜单对话框 -->
    <el-dialog :title="title" v-model="open" width="680px" append-to-body>
      <el-form ref="formRef" :model="form" :rules="rules" label-width="100px">
        <el-row>
          <el-col :span="24">
            <el-form-item label="上级菜单" prop="parentId">
              <el-tree-select
                v-model="form.parentId"
                :data="menuOptions"
                check-strictly
                :props="treeProps"
                :render-after-expand="false"
              />
            </el-form-item>
          </el-col>
          <el-col :span="24">
            <el-form-item label="菜单类型" prop="menuType">
              <el-radio-group v-model="form.menuType">
                <el-radio label="M">目录</el-radio>
                <el-radio label="C">菜单</el-radio>
                <el-radio label="F">按钮</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="24" v-if="form.menuType != 'F'">
            <el-form-item label="菜单图标" prop="icon">
              <el-input v-model="form.icon" placeholder="请输入图标标识"></el-input>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="菜单名称" prop="menuName">
              <el-input v-model="form.menuName" placeholder="请输入菜单名称" />
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item label="显示排序" prop="orderNum">
              <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item prop="isFrame">
              <el-tooltip effect="dark" content="选择是外链则路由地址需要以`http(s)://`开头" placement="top">
                <el-icon class="icon-item">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
              <template #label>
                <span style="position: relative">是否外链</span>
              </template>
              <el-radio-group v-model="form.isFrame">
                <el-radio :label="0">是</el-radio>
                <el-radio :label="1">否</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item prop="path">
              <el-tooltip content="访问的路由地址，如：`user`，如外网地址需内链访问则以`http(s)://`开头" placement="top">
                <el-icon class="icon-item-radio">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
              <template #label>
                <span style="position: relative">路由地址</span>
              </template>
              <el-input v-model="form.path" placeholder="请输入路由地址" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType == 'C'">
            <el-form-item prop="component">
              <el-tooltip effect="dark" content="访问的组件路径，如：`system/user/index`，默认在`views`目录下" placement="top">
                <el-icon class="icon-item">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
              <template #label>
                <span style="position: relative">组件路径</span>
              </template>
              <el-input v-model="form.component" placeholder="请输入组件路径" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType != 'M'">
            <el-form-item prop="perms">
              <el-tooltip
                effect="dark"
                content="控制器中定义的权限字符，如：@PreAuthorize(`@ss.hasPermi('system:user:list')`)"
                placement="top"
              >
                <el-icon class="icon-item">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
              <template #label>
                <span style="position: relative">权限字符</span>
              </template>
              <el-input v-model="form.perms" placeholder="请输入权限标识" maxlength="100" />
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType == 'C'">
            <el-form-item prop="query">
              <el-input v-model="form.query" placeholder="请输入路由参数" maxlength="255" />
              <el-tooltip effect="dark" content="访问路由的默认传递参数，如：{'id': 1, 'name': 'ry'}" placement="top">
                <el-icon class="icon-item">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
              <template #label>
                <span style="position: relative">路由参数</span>
              </template>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType == 'C'">
            <el-form-item prop="isCache">
              <el-tooltip
                effect="dark"
                content="选择是则会被`keep-alive`缓存，需要匹配组件的`name`和地址保持一致"
                placement="top"
              >
                <el-icon class="icon-item">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
              <template #label>
                <span style="position: relative">是否缓存</span>
              </template>
              <el-radio-group v-model="form.isCache">
                <el-radio label="0">缓存</el-radio>
                <el-radio label="1">不缓存</el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12" v-if="form.menuType != 'F'">
            <el-form-item prop="visible">
              <el-tooltip effect="dark" content="选择隐藏则路由将不会出现在侧边栏，但仍然可以访问" placement="top">
                <el-icon class="icon-item">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
              <template #label>
                <span style="position: relative">显示状态</span>
              </template>
              <el-radio-group v-model="form.visible">
                <el-radio v-for="item in dict.type.sys_show_hide" :key="item.value" :label="item.value">
                  {{ item.label }}
                </el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
          <el-col :span="12">
            <el-form-item prop="status">
              <el-tooltip effect="dark" content="选择停用则路由将不会出现在侧边栏，也不能被访问" placement="top">
                <el-icon class="icon-item">
                  <QuestionFilled />
                </el-icon>
              </el-tooltip>
              <template #label>
                <span style="position: relative">菜单状态</span>
              </template>
              <el-radio-group v-model="form.status">
                <el-radio v-for="item in dict.type.sys_normal_disable" :key="item.value" :label="item.value">
                  {{ item.label }}
                </el-radio>
              </el-radio-group>
            </el-form-item>
          </el-col>
        </el-row>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button type="primary" @click="submitForm">确 定</el-button>
          <el-button @click="cancel">取 消</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import type { FormRules, FormInstance } from "element-plus";
import { ElMessage, ElMessageBox } from "element-plus";
import { nextTick, onMounted, reactive, ref } from "vue";
import { addMenuApi, delMenuApi, getMenuTreeSelectApi, getMeuByIdApi, updeMenuApi, getMenuListApi } from "@/api";

// 查询参数
const queryParams = reactive({
  menuName: "",
  phonenumber: "",
  status: "",
  pageNum: 1,
  pageSize: 10
});

// 搜索条件
const handleQuery = () => {
  getMenuList();
};

// 重置查询条件
const resetQuery = () => {
  queryParams.menuName = "";
  queryParams.status = "";
  getMenuList();
};

// 新增
const handleAdd = (row: any) => {
  formRef.value?.resetFields();
  title.value = "新增菜单";
  open.value = true;
  if (row != null && row.menuId) {
    form.value.parentId = row.menuId;
  } else {
    form.value.parentId = 0 as any;
  }
};

// 修改
const handleUpdate = async (row: any) => {
  try {
    title.value = "修改菜单";
    const res = await getMeuByIdApi(row.menuId);
    if (res.code === 200) {
      form.value = res.data;
      await nextTick();
      open.value = true;
    } else {
      ElMessage.error(res.message);
    }
  } catch (error) {
    ElMessage.error("获取菜单数据失败");
  }
};

// 删除
const handleDelete = (row: any) => {
  try {
    ElMessageBox.confirm("确定删除所勾选的菜单吗？删除之后数据将无法恢复", "系统提示", {
      type: "warning"
    }).then(async () => {
      const res = await delMenuApi(row.menuId);
      if (res.code === 200) {
        ElMessage.success("删除成功");
        getMenuList();
        getMenuTreeSelect();
      } else {
        ElMessage.error(res.message);
      }
    });
  } catch (error) {
    ElMessage.error("删除失败");
  }
};

// 展开/折叠
const toggleExpandAll = () => {
  refreshTable.value = false;
  isExpandAll.value = !isExpandAll.value;
  nextTick(() => {
    refreshTable.value = true;
  });
};

// 列表数据
const menuList = ref<any[]>([]);

// 表格刷新标识
const refreshTable = ref(true);

// 表格加载状态
const loading = ref(false);

const isExpandAll = ref(false);

const title = ref("");

// 对话框打开状态
const open = ref(false);

const formRef = ref<FormInstance>();

const treeProps = ref({
  label: "label",
  value: "id"
});

// 表单数据
const form = ref({
  menuId: undefined,
  parentId: undefined,
  menuType: "M",
  icon: "",
  menuName: "",
  orderNum: 0,
  isFrame: 1,
  path: "",
  component: "",
  perms: "",
  query: "",
  isCache: 0,
  visible: "0",
  status: "0"
});

// 表单验证规则
const rules = reactive<FormRules>({
  menuName: [
    { required: true, message: "请输入菜单名称", trigger: "blur" },
    { min: 2, max: 50, message: "长度在 2 到 50 个字符", trigger: "blur" }
  ],
  orderNum: [
    { required: true, message: "请输入显示排序", trigger: "blur" },
    { type: "number", message: "显示排序必须为数字", trigger: "blur" }
  ],
  path: [
    { required: true, message: "请输入路由地址", trigger: "blur" },
    { min: 2, max: 255, message: "长度在 2 到 255 个字符", trigger: "blur" }
  ],
  component: [
    { required: true, message: "请输入组件路径", trigger: "blur" },
    { min: 2, max: 255, message: "长度在 2 到 255 个字符", trigger: "blur" }
  ],
  // perms: [
  //   { required: true, message: "请输入权限标识", trigger: "blur" },
  //   { min: 2, max: 100, message: "长度在 2 到 100 个字符", trigger: "blur" }
  // ],
  query: [{ min: 0, max: 255, message: "长度在 0 到 255 个字符", trigger: "blur" }]
});

// 菜单选项
const menuOptions = ref<any[]>([]);

// 获取菜单树选择
const getMenuTreeSelect = async () => {
  try {
    const res = await getMenuTreeSelectApi();
    if (res.code === 200) {
      const menu = { id: 0, label: "主类目", children: [] };
      menu.children = res.data;
      menuOptions.value.push(menu);
    } else {
      ElMessage.error(res.message);
    }
  } catch (error) {
    console.error("获取菜单失败");
  }
};

// 字典数据
const dict: { type: { [key: string]: { value: string; label: string }[] } } = {
  type: {
    sys_normal_disable: [
      { value: "0", label: "正常" },
      { value: "1", label: "停用" }
    ],
    sys_show_hide: [
      { value: "0", label: "显示" },
      { value: "1", label: "隐藏" }
    ]
  }
};

// 新增接口
const addMenu = async () => {
  try {
    const res = await addMenuApi(form.value);
    if (res.code === 200) {
      ElMessage.success("新增成功");
      open.value = false;
      getMenuList();
      formRef.value!.resetFields();
    } else {
      ElMessage.error(res.message);
    }
  } catch (error) {
    console.error("新增失败");
  }
};

// 修改接口
const updateMenu = async () => {
  try {
    const res = await updeMenuApi(form.value);
    if (res.code === 200) {
      ElMessage.success("修改成功");
      open.value = false;
      formRef.value!.resetFields();
      getMenuList();
    } else {
      ElMessage.error(res.message);
    }
  } catch (error) {
    console.error("修改失败");
  }
};

// 提交表单
const submitForm = () => {
  if (!formRef.value) return;
  formRef.value.validate(async (valid: boolean) => {
    if (!valid) return;

    if (title.value === "修改菜单") {
      // 修改
      updateMenu();
    } else {
      // 新增
      addMenu();
    }
  });
};

// 取消操作
const cancel = () => {
  open.value = false;
  formRef.value!.resetFields();
};

// 根据menuId处理成树形结构，比如handleTree(response.data, "menuId");
const handleTree = (data: any, id: string) => {
  const result: any = [];
  const map = new Map();
  data.forEach((item: any) => {
    map.set(item[id], item);
  });
  data.forEach((item: any) => {
    const parent = map.get(item.parentId);
    if (parent) {
      (parent.children || (parent.children = [])).push(item);
    } else {
      result.push(item);
    }
  });
  return result;
};

// 获取菜单列表
const getMenuList = async () => {
  try {
    const res = await getMenuListApi(queryParams);
    if (res.code === 200) {
      menuList.value = handleTree(res.data, "menuId");
    } else {
      ElMessage.error(res.message);
    }
  } catch (error) {
    console.error("获取菜单列表失败");
  }
};

// 组件挂载后获取列表
onMounted(() => {
  getMenuList();
  getMenuTreeSelect();
});
</script>

<style scoped lang="scss">
.demo-form-inline .el-input {
  --el-input-width: 220px;
}
.dialog-footer {
  display: flex;
  justify-content: flex-end;
}

.icon-item {
  position: absolute;
  left: -85px;
}

.icon-item-radio {
  position: absolute;
  left: -95px;
}
</style>
